package com.easylinkin.linkappapi.meterbilling.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.StringUtil;
import com.easylinkin.linkappapi.meterbilling.entity.RechargeRecord;
import com.easylinkin.linkappapi.meterbilling.entity.ResidentInfo;
import com.easylinkin.linkappapi.meterbilling.entity.RoomInfo;
import com.easylinkin.linkappapi.meterbilling.entity.RoomTenantryInfo;
import com.easylinkin.linkappapi.meterbilling.entity.ext.*;
import com.easylinkin.linkappapi.meterbilling.mapper.RechargeRecordMapper;
import com.easylinkin.linkappapi.meterbilling.mapper.ResidentInfoMapper;
import com.easylinkin.linkappapi.meterbilling.mapper.RoomInfoMapper;
import com.easylinkin.linkappapi.meterbilling.mapper.RoomTenantryInfoMapper;
import com.easylinkin.linkappapi.meterbilling.service.RechargeService;
import com.easylinkin.linkappapi.meterbilling.service.RoomManagerService;
import com.easylinkin.linkappapi.meterbilling.service.ThirdPayService;
import com.easylinkin.linkappapi.meterbilling.util.MeterServiceControl;
import com.easylinkin.linkappapi.meterbilling.util.RechargeConstant;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * class info :
 *
 * @author liuqihang
 * @date 2021/7/15 9:58
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RechargeServiceImpl extends ServiceImpl<RechargeRecordMapper, RechargeRecord> implements RechargeService {

    @Resource
    private RoomTenantryInfoMapper roomTenantryInfoMapper;

    @Resource
    private RoomInfoMapper roomInfoMapper;

    @Resource
    private ResidentInfoMapper residentInfoMapper;

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private ThirdPayService thirdPayService;

    @Resource
    private RoomManagerService roomManagerService;
    @Resource
    private MeterServiceControl meterServiceControl;

    @Value("${wechat.pay.jump_url}")
    public String jumpUrl;

    @Override
    public String addBalance(RechargeRecord rechargeRecord) {
        RoomTenantryInfo roomTenantryInfo = roomTenantryInfoMapper.selectById(rechargeRecord.getContractId());
        if(roomTenantryInfo == null){
            throw new IllegalArgumentException("不存在此住户合同信息");
        }

        //创建订单
        RoomInfo roomInfo = roomInfoMapper.selectById(roomTenantryInfo.getRoomId());
        pcFillOrderInfo(rechargeRecord);
        rechargeRecord.setType(0);
        baseMapper.insert(rechargeRecord);

        //修改房间水电表余额
        BigDecimal balance = new BigDecimal(0.0);
        balance = balance.add(rechargeRecord.getPrice());

        if(RechargeConstant.RECHARGE_TYPE_WATER == rechargeRecord.getRechargeType()){
            balance = balance.add(roomInfo.getWaterBalance());
            roomInfo.setWaterBalance(balance);
        }else if(RechargeConstant.RECHARGE_TYPE_ELECTRICITY == rechargeRecord.getRechargeType()){
            balance = balance.add(roomInfo.getElectricityBalance());
            roomInfo.setElectricityBalance(balance);
        }else {
            throw new IllegalArgumentException("未知充值类型");
        }
        roomInfoMapper.updateById(roomInfo);
        meterServiceControl.executeDeviceCommand(roomInfo);
        //订单成功
        rechargeRecord.setNotifyTime(LocalDateTime.now());
        rechargeRecord.setRechargeStatus(RechargeConstant.RECHARGE_STATUS_SUCCESS);
        baseMapper.updateById(rechargeRecord);
        return null;
    }

    @Override
    public Object[] deductionBalanceForDeleteRoom(Integer roomId, BigDecimal waterBalance, BigDecimal electricityBalance) {
        Object[] result = new Object[2];
        RoomInfo roomInfo = roomInfoMapper.selectById(roomId);

        roomInfo.setWaterBalance(new BigDecimal(0.0)).setElectricityBalance(new BigDecimal(0.0));
        roomInfoMapper.updateById(roomInfo);
        meterServiceControl.executeDeviceCommand(roomInfo);

        QueryWrapper qw = new QueryWrapper();
        qw.eq("room_id", roomId);
        qw.eq("bind_status", 0);
        qw.eq("delete_status", 0);
        List<RoomTenantryInfo> roomTenantryInfoList = roomTenantryInfoMapper.selectList(qw);
        if(roomTenantryInfoList == null || roomTenantryInfoList.isEmpty()){
            result[0] = false;
            result[1] = "未找到住户合同信息";
            return result;
        }

        if(waterBalance != null){
            RechargeRecord rechargeRecordWater = new RechargeRecord();
            pcFillOrderInfo(rechargeRecordWater);
            rechargeRecordWater.setType(1);
            rechargeRecordWater.setRechargeStatus(1);
            rechargeRecordWater.setContractId(roomTenantryInfoList.get(0).getId());
            rechargeRecordWater.setRechargeType(0);
            rechargeRecordWater.setPrice(waterBalance);
            baseMapper.insert(rechargeRecordWater);
        }

        if(electricityBalance != null){
            RechargeRecord rechargeRecordElectricity = new RechargeRecord();
            pcFillOrderInfo(rechargeRecordElectricity);
            rechargeRecordElectricity.setType(1);
            rechargeRecordElectricity.setRechargeStatus(1);
            rechargeRecordElectricity.setContractId(roomTenantryInfoList.get(0).getId());
            rechargeRecordElectricity.setRechargeType(1);
            rechargeRecordElectricity.setPrice(electricityBalance);
            baseMapper.insert(rechargeRecordElectricity);
        }

        result[0] = true;
        result[1] = "success";
        return result;
    }

    @Override
    public RechargeRecord getRechargeRecordInfo(RechargeRecord rechargeRecord) {
        QueryWrapper qw = new QueryWrapper();
        if(!StringUtils.isEmpty(rechargeRecord.getRechargeStatus())){
            qw.eq("recharge_status", rechargeRecord.getRechargeStatus());
        }
        if(!StringUtils.isEmpty(rechargeRecord.getThirdOrderNum())){
            qw.eq("third_order_num", rechargeRecord.getThirdOrderNum());
        }
        List<RechargeRecord> list = baseMapper.selectList(qw);
        if(ObjectUtils.isEmpty(list)){
            return null;
        }
        return list.get(0);
    }

    @Override
    public RestMessage createWXOrder(WechatRechargeInfo wechatRechargeInfo) {
        if(wechatRechargeInfo.getMoney().compareTo(new BigDecimal(0.0)) <= 0){
            return RestBuilders.failureBuilder().message("充值金额错误").build();
        }
        String phone = linkappUserContextProducer.getCurrentUsername();
        if(StringUtils.isEmpty(phone)){
            return RestBuilders.failureBuilder().message("未获取到登录用户信息").build();
        }
        List<ResidentInfo> residentInfoList = checkPhoneIsExistResident(phone);
        if(ObjectUtils.isEmpty(residentInfoList)){
            return RestBuilders.failureBuilder().message("此用户信息不存在").build();
        }
        ResidentInfo residentInfo = residentInfoList.get(0);
        String orderNum = System.currentTimeMillis() + StringUtil.getRandomByLength(6);
        RechargeRecord rechargeRecord = new RechargeRecord();
        rechargeRecord.setOrderNum(orderNum);

        RespOrderInfo respOrderInfo = new RespOrderInfo();
        try {
            //发起第三方post请求
            ThirdPayResult order = thirdPayService.createOrder(wechatRechargeInfo.getMoney());
            if(order != null && !order.getCode().equals(RechargeConstant.RECHARGE_RESP_OK)){
                respOrderInfo.setThirdCode(-1).setMessage("充值订单创建失败");
                return RestBuilders.failureBuilder().data(respOrderInfo).build();
            }

            GlobalRoomInfo globalRoomInfo = roomManagerService.getGlobalRoomInfo(wechatRechargeInfo.getRoomId());
            if(globalRoomInfo == null){
                return RestBuilders.failureBuilder().message("未获取到房间信息").build();
            }
            RoomTenantryInfo roomTenantryInfo = globalRoomInfo.getRoomTenantryInfo();

            ThirdPayDataResult data = order.getData();
            rechargeRecord.setThirdOrderNum(data.getOutTradeNo());
            rechargeRecord.setRechargeType(wechatRechargeInfo.getRechargeType());
            rechargeRecord.setPrice(wechatRechargeInfo.getMoney());
            rechargeRecord.setContractId(roomTenantryInfo.getId());
            rechargeRecord.setTenantId(roomTenantryInfo.getTenantId());
            rechargeRecord.setPayer(residentInfo.getName());
            //创建订单
            wxFillOrderInfo(rechargeRecord);
            rechargeRecord.setType(0);
            baseMapper.insert(rechargeRecord);

            //封装创建订单响应结果
            respOrderInfo.setThirdCode(200)
                    .setMessage("充值订单创建成功")
                    .setOrderNo(data.getOutTradeNo())
                    .setJumpUrl(jumpUrl + data.getOutTradeNo());
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        return RestBuilders.successBuilder().data(respOrderInfo).build();
    }

    @Override
    public void asynThirdNotify(Map<String, String[]> parameterMap, HttpServletResponse response) {
        Map<String, Object> params = thirdPayService.getParams(parameterMap);
        log.info("LinkThings支付回调响应参数：{}", parameterMap);
        if(thirdPayService.checkSign(params)){
            // 2.验证业务参数
            String return_outPayNo = String.valueOf(params.get("outTradeNo"));
            RechargeRecord rr = new RechargeRecord();
            rr.setThirdOrderNum(return_outPayNo);
            rr.setRechargeStatus(0);
            RechargeRecord sourceRechargeRecord = getRechargeRecordInfo(rr);
            if(sourceRechargeRecord == null){
                log.error("无此订单， return_outPayNo=" + return_outPayNo);
                return ;
            }

            String return_amount = String.valueOf(params.get("payAmount"));
            if(StringUtils.isEmpty(return_amount)){
                log.error(return_outPayNo + "订单的return_amount不能为空");
                return ;
            }
            BigDecimal dbMoney = sourceRechargeRecord.getPrice().multiply(new BigDecimal(100));
            if(dbMoney.compareTo(new BigDecimal(return_amount)) != 0){
                log.error(return_outPayNo + "订单的return_amount和创建的订单金额不匹配");
                return ;
            }
            //0 未支付 1 支付成功
            String return_payStatus = String.valueOf(params.get("payStatus"));
            if(!StringUtils.isEmpty(return_payStatus)){

                //修改充值订单状态
                QueryWrapper qw = new QueryWrapper();
                qw.eq("recharge_status", 0);
                qw.eq("third_order_num", return_outPayNo);

                RechargeRecord rr2 = new RechargeRecord();
                rr2.setNotifyTime(LocalDateTime.now());

                if( "1".equals(return_payStatus)){
                    //根据类型修改房间金额

                    RoomTenantryInfo roomTenantryInfo = roomTenantryInfoMapper.selectById(sourceRechargeRecord.getContractId());
                    RoomInfo roomInfo = roomInfoMapper.selectById(roomTenantryInfo.getRoomId());
                    BigDecimal balance = new BigDecimal(0.0);
                    balance = balance.add(sourceRechargeRecord.getPrice());
                    if(RechargeConstant.RECHARGE_TYPE_WATER == sourceRechargeRecord.getRechargeType()){
                        balance = balance.add(roomInfo.getWaterBalance());
                        roomInfo.setWaterBalance(balance);
                    }else if(RechargeConstant.RECHARGE_TYPE_ELECTRICITY == sourceRechargeRecord.getRechargeType()){
                        balance = balance.add(roomInfo.getElectricityBalance());
                        roomInfo.setElectricityBalance(balance);
                    }else {
                        throw new IllegalArgumentException("未知充值类型");
                    }
                    roomInfoMapper.updateById(roomInfo);
                    rr2.setRechargeStatus(1);
                    meterServiceControl.executeDeviceCommand(roomInfo);
                }else {
                    rr2.setRechargeStatus(2);
                }
                baseMapper.update(rr2, qw);
            }

            // 3.返回
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html; charset=utf-8");
            PrintWriter writer = null;
            try {
                writer = response.getWriter();
                Map<String,Object> result = new HashMap<>();
                result.put("code",200);
                result.put("message","SUCCESS");
                writer.write(JSON.toJSONString(result));
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                writer.close();
            }
        }
    }

    @Override
    public RestMessage askOrderStatus(String orderNo) {
        String askResult = thirdPayService.askOrderStatus(orderNo);
        if(StringUtils.isEmpty(askResult)){
            return RestBuilders.failureBuilder().message("询问无结果返回").build();
        }
        AskOrderResult askOrderResult = JSON.parseObject(askResult, AskOrderResult.class);
        if(askOrderResult.getCode() != null && !askOrderResult.getCode().equals(200)){
            return RestBuilders.failureBuilder().message("询问响应失败, " + askOrderResult.getMessage()).build();
        }
        if("NOT PAY".equals(askOrderResult.getData().getTradeState())){
            return RestBuilders.failureBuilder().message("未支付").build();
        }
        return RestBuilders.successBuilder().message("已支付").build();
    }


    private List<ResidentInfo> checkPhoneIsExistResident(String phone){
        QueryWrapper qw = new QueryWrapper();
        qw.eq("phone",phone);
        qw.eq("delete_status",0);
        List<ResidentInfo> residentInfoList = residentInfoMapper.selectList(qw);
        return residentInfoList;
    }

    private void pcFillOrderInfo(RechargeRecord rechargeRecord){
        LinkappUser current = linkappUserContextProducer.getCurrent();
        rechargeRecord.setOperator(current.getId().toString());
        rechargeRecord.setTenantId(current.getTenantId());

        rechargeRecord.setCreateTime(LocalDateTime.now());
        rechargeRecord.setOrderNum(System.currentTimeMillis() + StringUtil.getRandomByLength(6));
        rechargeRecord.setPayType(RechargeConstant.PAY_TYPE_CASH);
        rechargeRecord.setRechargePlatform(RechargeConstant.RECHARGE_PLATFORM_PC);
        rechargeRecord.setRechargeStatus(RechargeConstant.RECHARGE_STATUS_CREATE);
    }

    private void wxFillOrderInfo(RechargeRecord rechargeRecord){
        rechargeRecord.setCreateTime(LocalDateTime.now());
        rechargeRecord.setOrderNum(System.currentTimeMillis() + StringUtil.getRandomByLength(6));
        rechargeRecord.setPayType(RechargeConstant.PAY_TYPE_WECHAT);
        rechargeRecord.setRechargePlatform(RechargeConstant.RECHARGE_PLATFORM_PC);
        rechargeRecord.setRechargeStatus(RechargeConstant.RECHARGE_STATUS_CREATE);
        rechargeRecord.setPayTime(LocalDateTime.now());
    }



}
